package com.zxd.interview.eightthread.threadsafeerror;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程安全问题：
 * 两个线程累加，发现结果达不到期望结果
 *
 * 升级版本：
 * 1. 知道了会有线程安全问题
 * 2. 知道在什么地方会有线程安全问题
 */
public class ThreadSafeErrorTwoThreadImpose implements Runnable{

    private int count = 0;

    private final boolean[] flags = new boolean[200000];

    static volatile CyclicBarrier cyclicBarrier1 = new CyclicBarrier(2);
    static volatile CyclicBarrier cyclicBarrier2 = new CyclicBarrier(2);



    private static ThreadSafeErrorTwoThreadImpose threadSafeErrorTwoThread = new ThreadSafeErrorTwoThreadImpose();

    /**
     * 源自类标记实际的变量
     */
    private static AtomicInteger realIndex = new AtomicInteger();

    /**
     * 计算错误的条数
     */
    private static AtomicInteger errorCount = new AtomicInteger();



    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(threadSafeErrorTwoThread);

        Thread thread2 = new Thread(threadSafeErrorTwoThread);

        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("Sum count sum => "+ threadSafeErrorTwoThread.count);
        System.out.println("RealIndex  => "+ realIndex.get());
        System.out.println("ErrorCount  => "+ errorCount.get());
    }

    @Override
    public void run() {
        for (int index = 0; index < 10000; index++) {
            try {
                // 第一个挡板开启等待，第二个挡板释放
                cyclicBarrier2.reset();
                cyclicBarrier1.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            // 这里等待之后同时释放两个线程实现争夺效果
            count++;
            // 设置线程屏障，需要等待两个线程都准备完成之后，才能进行新一轮的争夺
            try {
                // 如果i++之后，则挡板 1 需要释放，第二个继续阻挡
                cyclicBarrier1.reset();
                cyclicBarrier2.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }

            realIndex.incrementAndGet();
            // 这里我们让另一个线程观察到当前标志位被置换，所以如果重复判断则认为是出现相同值的情况。
            synchronized (threadSafeErrorTwoThread){
                if(flags[count] && flags[count-1]){
                    errorCount.incrementAndGet();
                    System.out.println("发生错误："+ count);
                }
            }
            flags[count] = true;

        }
    }/**运行结果
        每次运行结果都不一样，但是很难有正确结果
     */
}
